#include "Hotplug.h"





CHotplug :: CHotplug()
{
   HotplugEventList.clear();
   memset(&hotplug, 0, sizeof(hotplug));
   memset(uevent_buff, 0, sizeof(uevent_buff));
}

CHotplug :: ~CHotplug()
{
    
    if(hotplug.is_start == 0) //如果线程还没有启动
    {
        MY_ERROR_LOG("[hotplug] start_hotplug_monitor had not start.\n");
        return;
    }
    hotplug.is_running = 0; 
    HotplugUnInit();
}

int CHotplug :: HotplugInit()
{
    if(HotplugCreateUEvent())
        {
            MY_ERROR_LOG("[hotplug_core] create_uevent_socket fail.\n");
            hotplug.is_start = 0;
            return -1;
        }
    hotplug.epoll_fd = epoll_create(EPOLL_FD_SIZE);
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = hotplug.uevent_fd;
    epoll_ctl(hotplug.epoll_fd,EPOLL_CTL_ADD,hotplug.uevent_fd,&ev);  //监听fd
    hotplug.is_running = 1;
    return 0;
   
}

int CHotplug :: HotplugUnInit()
{
    hotplug.is_start = 0;
    HotplugDestoryUEvent();
    close(hotplug.epoll_fd);
   
}


void CHotplug :: HotplugRegisterEvent(const char *dev_str, HotplugCb cb, void *data)
{
   HotplugEvent_t temp = {0};
   temp.cb = cb;
   temp.data = data;
   HotplugEventList[dev_str] = temp;
}

void CHotplug :: HotplugUnRegisterEvent(const char *dev_str)
{
   HotplugEventList.erase(HotplugEventList.find(dev_str));
}

int CHotplug :: HotplugCreateUEvent()
{
    int flags,retval;
    hotplug.uevent_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if(hotplug.uevent_fd<0)
    {
        MY_ERROR_LOG("[hotplug] create_uevent_socket socket fail.\n");
        return -1;
    }
    flags = fcntl(hotplug.uevent_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(hotplug.uevent_fd, F_SETFL, flags);
    struct sockaddr_nl src_addr;
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();
    src_addr.nl_groups = 0xffffffff;
    retval = bind(hotplug.uevent_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
    if(retval < 0)
    {
        MY_ERROR_LOG("[hotplug] create_uevent_socket bind fail.\n");
        close(hotplug.uevent_fd);
        hotplug.uevent_fd = 0;
        return -1;
    }
    return 0;

}


void CHotplug :: HotplugDestoryUEvent()
{
    if(hotplug.uevent_fd>0)
     {
         close(hotplug.uevent_fd);
         hotplug.uevent_fd = 0;
     }
}


void CHotplug :: HotplugPraseUEvent(char* recv_buff,int recv_size)
{
     int i = 0;
     char* p_str = recv_buff;
     for(i=0;i<recv_size;i++)
     {
         if(recv_buff[i] == '\0')
         {
             if(strstr(p_str,"add") != NULL)  //添加设置
             {
                for(map<string, HotplugEvent_t>::iterator item = HotplugEventList.begin(); 
                          item != HotplugEventList.end(); item++)
                    {
                          if(strstr(p_str, item->first.c_str())!= NULL && item->second.devstatus != HOTPLUG_ADD)
                              {
                                  item->second.cb(item->first.c_str(), HOTPLUG_ADD, item->second.data);
                                  item->second.devstatus = HOTPLUG_ADD;
                              }
                    }
             }
             else if(strstr(p_str,"remove") != NULL) //移除设备
             {
                 for(map<string, HotplugEvent_t>::iterator item = HotplugEventList.begin(); 
                          item != HotplugEventList.end(); item++)
                    {
                          if(strstr(p_str, item->first.c_str())!= NULL && item->second.devstatus != HOTPLUG_REMOVE)
                              {
                                  item->second.cb(item->first.c_str(), HOTPLUG_REMOVE, item->second.data);
                                  item->second.devstatus = HOTPLUG_REMOVE;
                              }
                    }
             }
             p_str = recv_buff+(i+1); // i+1 是为了指到\0 后面的一个字符
         }
     }

}


int CHotplug :: HotplugSchedule(void *arg)
{
    //  prctl(PR_SET_NAME, "HOTPLUG");
    //  MY_ERROR_LOG("HOTPLUG Thread start\n");
   
    
        int i,ret,recv_size;
        struct epoll_event events[EPOLL_EVENT_SIZE];
        if(hotplug.is_running)
        {
            ret = epoll_wait(hotplug.epoll_fd,events,EPOLL_EVENT_SIZE,EPOLL_TIMEOUT);  //等待节点
            for(i=0;i<ret;i++)
            {
                // 判断是否是要监听的节点可读
                if((events[i].data.fd == hotplug.uevent_fd) && (events[i].events&EPOLLIN))
                {
                recv_size = recv(hotplug.uevent_fd, uevent_buff, KERNEL_UEVENT_LEN, 0);
                if(recv_size > KERNEL_UEVENT_LEN)
                {
                    MY_ERROR_LOG("[hotplug] receive overflow!\n");
                    continue;
                }
                HotplugPraseUEvent(uevent_buff,recv_size);
                }
            }
        }

        return 0;


}